#pragma once

#include "rewine/impl/CImport.hpp"

#include "wininc/pe.h"

#include <memory>
#include <string>
#include <vector>
#include <wininc/pe.h>

namespace rewine
{

class IImage;

class CPeImport : public CImport<IMAGE_THUNK_DATA> {
private:

    DWORD       m_Ordinal = 0;
    WORD        m_Hint;

    PIMAGE_THUNK_DATA m_IltEntry; // ro
    PIMAGE_THUNK_DATA m_IatEntry; // rw

protected:

    IMAGE_THUNK_DATA convertPointerToSlotValue(void *p) const override {
        IMAGE_THUNK_DATA s;
        s.u1.Function = reinterpret_cast<typeof(s.u1.Function)>(p);
        return s;
    }

    void * convertSlotValueToPointer(IMAGE_THUNK_DATA s) const override {
        return reinterpret_cast<void *>(s.u1.Function);
    }

public:

    CPeImport() = default;
    ~CPeImport() override = default;

public:

    void setImport(UINT index, PIMAGE_THUNK_DATA iltEntry, PIMAGE_THUNK_DATA iatEntry) {
        setIndex(index);
        m_IltEntry = iltEntry;
        m_IatEntry = iatEntry;
        setSlotAddress(m_IatEntry);
    }

    void setOrdinal(DWORD ordinal) {
        m_Ordinal = ordinal;
    }

    void setHintAndName(WORD hint, const std::string& name) {
        m_Hint = hint;
        CImport::setName(name);
    }

public:

    std::string getName() const override {
        if (m_Ordinal) {
            return std::string("#") + std::to_string(m_Ordinal);
        }
        return CImport::getName();
    }

    WORD getHint() const {
        return m_Hint;
    }

};


class CPeImportLib {
private:

    UINT m_Index;
    std::string m_Name;

    UINT m_NbSymbol;
    std::vector<std::shared_ptr<CPeImport>> m_Symbols;

public:

    CPeImportLib() = default;
    ~CPeImportLib() = default;

    void setName(UINT index, const std::string& name) {
        m_Index = index;
        m_Name = name;
    }

    void clearSymbols(UINT nbSymbol) {
        m_Symbols.clear();
        m_Symbols.reserve(nbSymbol);
        m_NbSymbol = nbSymbol;
    }

    void addSymbol(const std::shared_ptr<CPeImport>& pImport) {
        m_Symbols.push_back(pImport);
    }

public:

    UINT getIndex() const {
        return m_Index;
    }

    std::string getName() const {
        return m_Name;
    }

};

} // namespace rewine
